package net.media.datafw.database;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.HashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.media.datafw.database.model.Query;
import net.media.datafw.database.pool.ConnectionPool;

public class DataBaseConnection {
	Logger logger = LoggerFactory.getLogger(getClass());

	private boolean markedForClose;
	private Connection connection;
	private ConnectionPool connectionPool;
	private ConnectionManager connectionManager;
	private int numQueriesExecuted = 0;

	protected final HashMap<Query, PreparedStatement> preparedStatements = new HashMap<Query, PreparedStatement>();

	public DataBaseConnection(Connection connection, ConnectionManager connectionManager, ConnectionPool connectionPool) {
		this.connection = connection;
		this.connectionManager = connectionManager;
		this.connectionPool = connectionPool;
	}

	public PreparedStatement prepareStatement(Query query) throws DataBaseException {
		PreparedStatement preparedStatement = null;
		try {
			preparedStatement = this.connection.prepareStatement(query.getQuery(), query.getResultsetType(), query.getResultsetConcurrency());
		} catch (SQLException e) {
			throw new DataBaseException(e);
		}
		return preparedStatement;
	}

	public PreparedStatement getStatement(Query query) throws DataBaseException {
		PreparedStatement preparedStatement = this.preparedStatements.get(query);
		if (preparedStatement == null) {
			preparedStatement = prepareStatement(query);
		}
		return preparedStatement;
	}

	public void setMarkedForClose(boolean markedForClose) {
		this.markedForClose = markedForClose;
	}

	public boolean isMarkedForClose() {
		return markedForClose;
	}

	public Connection getConnection() {
		return connection;
	}

	public ConnectionPool getConnectionPool() {
		return connectionPool;
	}

	public void closeConnection() {
		if (this.connection != null) {
			try {
				this.connection.close();
			} catch (SQLException e) {
				logger.error(e.getMessage(), e);
			}
			this.connection = null;
			preparedStatements.clear();
		}
	}

	void commit() throws SQLException {
		if (this.numQueriesExecuted > 0) {
			this.connection.commit();
		}
		this.numQueriesExecuted = 0;
	}

	void rollback() throws SQLException {
		if (this.numQueriesExecuted > 0) {
			this.connection.rollback();
		}
		this.numQueriesExecuted = 0;
	}

	public int getQueriesExecuted() {
		return numQueriesExecuted;
	}

	public boolean isConnectionClosed(String errorMessage) {
		boolean isClosed = false;
		try {
			isClosed = (this.connection == null || (errorMessage != null && errorMessage.indexOf("close") >= 0) || this.connection.isClosed());
		} catch (SQLException e) {
			isClosed = true;
		}
		return isClosed;
	}

	public void incrementQueriesExecuted() {
		numQueriesExecuted++;
	}

	public ConnectionManager getConnectionManager() {
		return connectionManager;
	}

	public void reOpen() {
		this.getConnectionManager().reOpenConnection(this);
	}

	public void setConnection(Connection connection) {
		this.connection = connection;
	}
}
